模块程序设计

  在这些年里,设计程序的着重点已经从有关过程的设计转移到对数据的组织了。除了其他因素之外,这种转移也反映了程序规模增大的情况。一集相关的过程与被它们所操作的数据组织在一起,通常被称做一个模块。程序设计的范型变成了:

    确定你需要哪些模块;将程序分成一些模块,使数据隐藏于模块之中。

这一范型也被作为数据隐藏原理而广为人知。在那些不存在与数据相关的过程组之处,采用过程式程序设计也就足够了。还有,设计“好过程”的技术现在可以应用到模块中的各个过程。有关模块的最常见的例子是定义一个堆栈。这里需要解决的主要问题是:

1)、为堆栈提供一个用户界面(例如,函数 push()pop())。

2)、保证堆栈的表示(例如,一个元素的数组)只能通过用户界面访问。

3)、保证堆栈在被使用之前已经做了初始化。

C++提供了一种机制,可以把相关的数据、函数等组织到一个独立的名字空间里。例如,模块Stack的用户界面可以按如下方式声明和使用:

    namespace Stack    // 界面
    {
        void push(char);
        char pop();
    }

    void f()
    {
        Stack::push('c');
        if(Stack::pop()!='c') error("impossible");
    }

这里的 Stack:: 限定词表明push()pop() 是来自Stack名字空间。这些名字的其他使用将不会与之干扰,不会引起混乱。

  Stack的定义可以通过程序的另一个单独编译的部分提供:

    namespace Stack    // 实现
    {
        const int max_size = 200;
        char v[max_size];
        int top = 0;

        void push(char c) { /* 检查上溢并压入c */ }
        char pop() { /* 检查下溢并弹出 */ }
    }

有关这个Stack模块的关键点是,用户代码完全被隔离于Stack的数据表示之外,隔离的方式是通过写出 Stack::push()Stack::pop() 代码来实现。用户不必知道Stack是用数组实现的,这个实现方式也可以修改,而不会影响用户的代码。这里以 /* 开始一段注释,以 */ 结束注释。

  数据实际上只是人们希望“隐藏”起来的许多东西中的一类,数据隐藏的概念很容易扩展到信息隐藏,也就是说,例如函数、类型等的名字,也很容易做成一个模块里面局部的东西。为此,C++允许把任何声明放到名字空间里。

  这个Stack模块只是描述堆栈的一种方式,下面几小节将用各种堆栈作为例子,阐释不同的程序设计风格。

🔚